package com.xxg.curd.impl;

import com.xxg.curd.CurdConfig;
import com.xxg.curd.SQL;
import com.xxg.curd.SQLMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by game group on 2020/12/31.
 */
public class BaseSQLImpl implements SQL {

    private final SQLMap sqlMap;

    public BaseSQLImpl(CurdConfig config){
        this.sqlMap = config.getSQLMap();
    }

    @Override
    public void createTable(String tableName, Map<String, Object> fieldsAndType, StringBuilder buffer) {
        buffer.append("CREATE TABLE `")
                .append(sqlMap.getTableName(tableName)).append("` (");
        fieldsAndType.remove("id");

        buffer.append("`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '唯一标识',");
        fieldsAndType.forEach((k,v) -> {
            String nk = sqlMap.getFieldName(tableName, k);
            if(!nk.equals(k)){
                v = v.toString().replaceAll(k, sqlMap.getFieldName(tableName, k));
            }
            buffer.append("`").append(nk).append("` ").append(v).append(" ,");
        });
        buffer.append("PRIMARY KEY (`id`)").append(") COLLATE='utf8_general_ci' ENGINE=InnoDB; ");
    }

    @Override
    public void dropTable(String tableName, StringBuilder sql) {
        sql.append("DROP TABLE `").append(sqlMap.getTableName(tableName)).append(String.format("`; "));
    }

    @Override
    public void add(String tableName, List<Map<String, Object>> params, List<StringBuilder> sqlList) {
        for (Map<String, Object> values : params) {
            StringBuilder builder = new StringBuilder().append("INSERT INTO `")
                    .append(sqlMap.getTableName(tableName)).append("` (");
            StringBuffer fields = new StringBuffer();
            StringBuffer vals = new StringBuffer();
            List<Map.Entry<String, Object>> entries = new ArrayList<>(values.entrySet());
            int len = entries.size() - 1;
            for (int i = 0; i < len; i++) {
                String key = entries.get(i).getKey();
                String value = entries.get(i).getValue().toString();

                String nKey = sqlMap.getFieldName(tableName,key);
                if(!key.equals(nKey)){
                    value = value.replaceAll(key,nKey);
                }


                fields.append("`").append(nKey).append("`, ");
                vals.append("\"").append(value).append("\",");
            }

            String key = entries.get(len).getKey();
            String value = entries.get(len).getValue().toString();
            String nKey = sqlMap.getFieldName(tableName,key);
            if(!key.equals(nKey)){
                value = value.replaceAll(key,nKey);
            }

            fields.append("`").append(nKey).append("` ");
            vals.append("\"").append(value).append("\"");
            builder.append(fields).append(") VALUES (").append(vals).append("); ");
            sqlList.add(builder);
        }
    }

    @Override
    public void deleteById(String tableName, List<String> ids, List<StringBuilder> sqlList) {
        for (String id : ids) {
            StringBuilder builder = new StringBuilder();
            builder.append("DELETE FROM  ").append(sqlMap.getTableName(tableName))
                    .append(" WHERE `id` = \"").append(id).append("\"");
            sqlList.add(builder);
        }
    }

    @Override
    public void updateById(String tableName, List<Map<String, Object>> params, List<StringBuilder> sqlList) {
        for (Map<String, Object> values : params) {
            StringBuilder builder = new StringBuilder().append("UPDATE ")
                    .append(sqlMap.getTableName(tableName)).append(" SET ");
            Object id = values.remove("id");
            values.forEach((k,v) -> {
                String nk = sqlMap.getFieldName(tableName, k);
                String nv = v.toString();
                if(!k.equals(nk)){
                    nv = nv.replaceAll(k,nk);
                }
                builder.append("`").append(nk).append("` = \"").append(nv).append("\",");
            });
            builder.deleteCharAt(builder.length() - 1);
            builder.append(" WHERE `id` = \"").append(id).append("\"");
            sqlList.add(builder);
        }
    }

    @Override
    public void findById(String tableName, List<String> ids, StringBuilder sql) {
        sql.append("SELECT * FROM ").append(sqlMap.getTableName(tableName)).append(" WHERE `id` in (")
            .append("\"").append(ids.get(0)).append("\"");
        for (int i = 1; i < ids.size(); i++) {
            sql.append(",\"").append(ids.get(i)).append("\"");
        }
        sql.append("); ");
    }

    @Override
    public void pageBy(String tableName, int skip, int size, Map<String, Object> where, StringBuilder buffer) {
        buffer.append("SELECT * FROM `")
                .append(sqlMap.getTableName(tableName)).append("` ");

        if (where.size() > 0) {
            buffer.append(" WHERE ");
            List<Map.Entry<String, Object>> entryList = where.entrySet().stream().collect(Collectors.toList());
            StringBuffer tem = new StringBuffer();
            for (int i = 0; i < entryList.size(); i++) {
                Map.Entry<String, Object> entry = entryList.get(i);
                CharSequence k = entry.getKey();
                Object v = entry.getValue();

                if(tem.length() != 0){
                    tem.append(" AND ");
                }

                if("$".equals(k)){
                    tem.append(v);
                }else if(k.charAt(0) == '$'){
                    String nk = k.toString().substring(1);
                    String nv = ((String) v).replaceAll(nk, String.format("`%s`", nk));

                    tem.append(" (").append(nv).append(") ");
                }else if(k.charAt(0) == '!'){
                    String nk = k.toString().substring(1);
                    tem.append("`").append(nk).append("` != ").append("\"").append(v).append("\" ");
                }else {
                    tem.append("`").append(k).append("` = ").append("\"").append(v).append("\" ");
                }
            }

            buffer.append(tem);
        }

        buffer.append(" LIMIT ").append(skip).append(",").append(size);
    }
}
